import wx
import wx.html
from LMG.GUI.Base.ArtManager import ArtManager

#######################################################################################
class TitlePanel(wx.Panel):
    """
    Helper class to draw gradient shadings on the dialog.
    """

    def __init__(self, parent, title):
        """
        Default class constructor.
        """

        wx.Panel.__init__(self, parent)
        self._title = title

        # Set the panel size
        dc = wx.MemoryDC()
        dc.SelectObject(wx.EmptyBitmap(1, 1))
        dc.SetFont(wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT))
        
        ww, hh = dc.GetTextExtent("Tp")
        dc.SelectObject(wx.NullBitmap)
        
        # Set minimum panel size
        if ww < 250:
            ww = 250

        self.SetBackgroundStyle(wx.BG_STYLE_PAINT)
        self.SetInitialSize(wx.Size(ww, hh + 10))
        self.Bind(wx.EVT_PAINT, self.OnPaint)

    def OnPaint(self, event):
        """
        Handles the wx.EVT_PAINT event for TitlePanel.
        """

        dc = wx.BufferedPaintDC(self)

        # Draw the background
        colour1 = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)
        colour2 = ArtManager.Get().LightColour(ArtManager.Get().getThemeColor(), 70)

        #dc.GradientFillLinear(self.GetClientRect(), colour1, colour2, wx.NORTH)
        if colour2 == wx.WHITE:
            dc.GradientFillLinear(self.GetClientRect(), colour1, colour2, wx.NORTH)
        else:
            dc.GradientFillLinear(self.GetClientRect(), colour1, colour2, wx.SOUTH)

        # Draw the text
        font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
        font.SetWeight(wx.BOLD)
        font.SetStyle(wx.FONTSTYLE_SLANT)
        dc.SetFont(font)
        dc.SetTextForeground(wx.BLACK)
        dc.DrawText(self._title, 5, 5)
        
class Gauge(wx.Gauge):
    """
    Native progress bar
    """
    def __init__(self, parent):
        self.parent = parent
        wx.Gauge.__init__(self, parent, -1, style = wx.NO_BORDER)

        # Event Table
        self.Bind(wx.EVT_LEFT_DOWN, self.onSelect)
        self.Bind(wx.EVT_MIDDLE_DOWN, self.onSelect)
        self.Bind(wx.EVT_RIGHT_DOWN, self.onRight)

    def onRight(self, event):
        self.onSelect(event)
        self.parent.onContextMenu()
        
    def onSelect(self, event):
        """
        Emulate selection of list item
        """
        try:
            selected = self.parent.progressBars.index(self)
            self.parent.updateSelected(unselect = range(0, self.parent.GetItemCount()), select = [selected])
            self.parent.SetFocus()
        except:
            pass
        
class ProgressBar(wx.PyControl):
    """
    A simple progress bar
    """    
    def __init__(self, parent):
        self.parent = parent
        wx.PyControl.__init__(self, parent, -1, style = wx.NO_BORDER)
        self.InheritAttributes()

        self.nothave_brush = wx.Brush(wx.Colour(220,250,220), wx.SOLID)

        self.size = self.buffer = None
##        self.size = self.GetClientSize()
##        self.buffer = wx.EmptyBitmap(*self.size)

        self.fractionDone = 0.0

        self.SetBackgroundStyle(wx.BG_STYLE_PAINT)
        
        # Event Table
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
        self.Bind(wx.EVT_LEFT_DOWN, self.onSelect)
        self.Bind(wx.EVT_MIDDLE_DOWN, self.onSelect)
        self.Bind(wx.EVT_RIGHT_DOWN, self.onRight)

    def onRight(self, event):
        self.onSelect(event)
        self.parent.onContextMenu()
        
    def onSelect(self, event):
        """
        Emulate selection of list item
        """
        try:
            selected = self.parent.progressBars.index(self)
            self.parent.updateSelected(unselect = range(0, self.parent.GetItemCount()), select = [selected])
            self.parent.SetFocus()
        except:
            pass
        
    def OnSize(self, event):
        """
        Catch the EVT_SIZE event
        """
        self.size = self.GetClientSize()
        self.buffer = wx.EmptyBitmap(*self.size)
        self.Refresh()
        event.Skip()
        
    def OnEraseBackground(self, event):
        """
        Avoid flickers
        """
        pass

    def OnPaint(self, event):
        """
        Catch the EVT_PAINT event
        """
        if self.buffer is None:
            self.size = self.GetClientSize()
            self.buffer = wx.EmptyBitmap(*self.size)
        dc = wx.BufferedPaintDC(self, self.buffer)
        self.DoDraw(dc)
        event.Skip()

    def DoDraw(self, dc):
        """
        Draw the control
        """
        size = self.size
        
        # Draw not have
        dc.SetBackground(self.nothave_brush)
        dc.Clear()

        # Draw have
        dc.GradientFillLinear((0, 0, size.width*self.fractionDone/100, size.height),
                              wx.Colour(50,180,50), wx.GREEN, wx.NORTH)

        # Draw Text
        string = str(self.fractionDone) + '%'
        dc.DrawText(string, int(size.width/2) - int(dc.GetTextExtent(string)[0]/2), -1)
                
    def AcceptsFocus(self):
        """ Overridden base class virtual. """
        return False
    
    def DoGetBestSize(self):
        """ Overridden base class virtual. """
        return self.size

    def SetValue(self, fractionDone):
        """
        Set the current progress
        """
        fractionDone = int(fractionDone*10)/10.0
        if fractionDone != self.fractionDone:
            self.fractionDone = fractionDone
            self.Refresh()
            
class ScrolledHtmlDialog(wx.Dialog):
    def __init__(self, parent, msg, caption,
                 pos=wx.DefaultPosition, size=(500,300),
                 style=wx.DEFAULT_DIALOG_STYLE):
        wx.Dialog.__init__(self, parent, -1, caption, pos, size, style)
        x, y = pos
        if x == -1 and y == -1:
            self.CenterOnScreen(wx.BOTH)

        sizer = wx.BoxSizer(wx.VERTICAL)
        
        self.text = wx.html.HtmlWindow(self, -1)
        self.text.SetPage(msg)
        self.text.SetBackgroundColour(wx.NullColour)
        
        sizer.Add(self.text, 1, wx.EXPAND|wx.ALL, 3)
        sizer.Add(self.CreateSeparatedButtonSizer(wx.OK), 0, wx.EXPAND|wx.GROW, 0)

        self.SetSizer(sizer)

class GraphRecord(object):
    def __init__(self, color, max_x = 100, max_y = 100, avg = 1):
        
        self.linepen = wx.Pen(color, 1, wx.SOLID)
        
        self.avg_over = avg
        
        self.max_x = max_x+1  # max relative y
        self.max_y = max_y+1  # max relative x
                
        self.value = 0
        self.cur_x = 0
        self.cur_y = 0

        self.avg_y = []
        
        self.screen_x = 0
        self.screen_y = 0        
        
        self.graph_area = [(0,0),(0,0)]    #to be recived OnSize
        
        self.line_data = [0] * (self.max_x)
        self.line = [wx.Point(0,0)] * (self.max_x)

    def SetYMax(self, y, size=False):
        self.max_y = max(1, y)
        if size:
            self.OnSize(self.graph_area)
    
    def OnSize(self, graph_area):
        self.graph_area = graph_area

        #resize graph
        ga = self.graph_area
        
        delta_x = float(ga[1][0] - ga[0][0]) / self.max_x 
        delta_y = float(ga[1][1] - ga[0][1]) / self.max_y
        x = 0
        for y in self.line_data:
            self.screen_x = int(ga[0][0] + x*delta_x)
            self.screen_y = ga[1][1] - y*delta_y
    
            if self.screen_y < ga[0][1]:
                self.screen_y = ga[0][1]
            if self.screen_y < ga[0][1]:
                self.screen_y = ga[1][1]            
                        
            self.line[x] = wx.Point( self.screen_x, self.screen_y )
            x += 1
        # Fix?
        self.screen_x = int(ga[0][0] + self.cur_x*delta_x)
            
    def ChangeColor(self, color):
        self.linepen = wx.Pen(color, 1, wx.SOLID)
    
    def AddValue(self, value):
        self.cur_y = value
        self.cur_x += 1
        ga = self.graph_area
        
        if self.cur_x >= self.max_x:
            self.cur_x = 1
            self.line_data[0] = self.line_data[self.max_x-1]
            self.line[0] = wx.Point( ga[0][0], self.line[self.max_x-1].y )
        
        delta_x = float(ga[1][0] - ga[0][0]) / self.max_x 
        delta_y = float(ga[1][1] - ga[0][1]) / self.max_y

        x = self.cur_x
        y = self.cur_y

        # avg y
        if self.avg_over > 1:
            if len(self.avg_y) > self.avg_over:
                self.avg_y.pop(0)                
            self.avg_y.append(y)
            sum = 0
            for v in self.avg_y:
                sum += v
            y = sum / self.avg_over
        
        self.screen_x = int(ga[0][0] + x*delta_x)
        self.screen_y = ga[1][1] - y*delta_y
        
        if self.screen_y < ga[0][1]:
            self.screen_y = ga[0][1]
        if self.screen_y < ga[0][1]:
            self.screen_y = ga[1][1]
        
        self.line_data[x] = y
        self.line[x] = wx.Point( self.screen_x, self.screen_y )
       
class Graph(wx.PyPanel):
    def __init__(self, parent, margin = 15, xaxis_text = "x", yaxis_text = "y", size = wx.DefaultSize):
        wx.PyPanel.__init__(self, parent, -1, size=size, style = wx.NO_BORDER|wx.NO_FULL_REPAINT_ON_RESIZE)
        self.InheritAttributes()

        # Colors
        self.gp_bgcolor = wx.Colour(255,255,255)
        self.gp_grapharea_c = wx.Colour(190,210,240)
        self.gp_grapharea_f = wx.Colour(100,100,140)
        
        # Brushes
        self.p_bars = wx.Pen(self.gp_grapharea_f, 1, wx.DOT)
        self.no_pen = wx.Pen(self.gp_bgcolor, 0, wx.SOLID)
        self.no_brush = wx.Brush(self.gp_bgcolor, wx.TRANSPARENT)
        self.bgbrush = wx.Brush(self.gp_bgcolor, wx.SOLID)
        self.grapharea = wx.Brush(self.gp_grapharea_c, wx.SOLID)
        self.grapharea_pen = wx.Pen(self.gp_grapharea_f, 2, wx.SOLID)
        self.grapharea_pen.SetCap(wx.CAP_BUTT)

        # Position and size
        self.xaxis_text = [xaxis_text, 8, wx.SWISS, wx.NORMAL, wx.NORMAL]
        self.yaxis_text = [yaxis_text, 8, wx.SWISS, wx.NORMAL, wx.NORMAL]
        self.client_size = size
        self.graph_area = [(margin,margin), (self.client_size[0]-margin,self.client_size[1]-margin)]
        self.margin = margin
        self.records = []
        
        self.size = self.buffer = None

        self.SetBackgroundStyle(wx.BG_STYLE_PAINT)
        
        # Event Table
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
      
    def UpdateGraph(self):
        if self.IsShown():
            self.Refresh()
            
    def GetMaxValue(self):
        if not self.records:
            return 0
        return max([max(record.line_data) for record in self.records])

    def SetYMax(self, y, size=False):
        for record in self.records:
            record.SetYMax(y, size)
        
    def GetGraphArea(self):
        return self.graph_area
    
    def AddRecord(self, record):
        record.OnSize(self.graph_area)
        if record not in self.records:
            self.records.append(record)

    def RemoveRecord(self, record):
        try:
            self.records.remove(record)
            return True
        except:
            return False

    def OnSize(self, event):
        """
        Catch the EVT_SIZE event
        """
        if not self.IsShown():
            return
        
        self.size = self.GetClientSize()
        self.buffer = wx.EmptyBitmap(*self.size)

        self.graph_area = [(self.margin, self.margin-10), (self.size[0]-self.margin, self.size[1]-self.margin)] 
        for record in self.records:
            record.OnSize(self.graph_area)

        self.Refresh()
        event.Skip()

    def OnEraseBackground(self, event):
        """
        Avoid flickers
        """
        pass
    
    def OnPaint(self, event):
        """
        Catch the EVT_PAINT event
        """
        if self.buffer is None:
            self.size = self.GetClientSize()
            self.buffer = wx.EmptyBitmap(*self.size)
        dc = wx.BufferedPaintDC(self, self.buffer)
        self.DoDraw(dc)
        event.Skip()
        
    def DoDraw(self, dc):
        """
        Draw the control
        """
        if not self.IsShown():
            return
        
        # some tmp locals
        if len(self.records) > 0:
            progress_line = True
        else:
            progress_line = False
            
        xaxis_text = self.xaxis_text
        yaxis_text = self.yaxis_text
        ga = self.graph_area
        
        dc.SetBackground(self.bgbrush)
        dc.Clear()
                
        #draw graph area rect
        dc.SetPen(self.no_pen)
        dc.SetBrush(self.grapharea)
        dc.DrawRectangle(ga[0][0], ga[0][1], ga[1][0]-ga[0][0], ga[1][1]-ga[0][1])
        
        #draw h_bars
        dc.SetPen(self.p_bars)
        h = ga[1][1] - ga[0][1]
        h_delta = float(h) / 10
        for i in range(1, 10):
            y = ga[0][1] + int(h_delta*i)
            dc.DrawLine(ga[0][0]+2, y, ga[1][0]-1, y)
                    
        # draw graph line (s)
        for record in self.records:
            dc.SetPen(record.linepen)
            dc.DrawLines(record.line[:record.cur_x+1])
            if record.max_x - (record.cur_x+1) > 1:
                dc.DrawLines(record.line[record.cur_x+1:])
                        
        # draw progress indicator line
        if progress_line:
            x = self.records[0].screen_x
            dc.SetPen(self.p_bars)
            dc.DrawLine(x, ga[0][1], x, ga[1][1])
            

        # draw bounding box around graph area
        dc.SetPen(self.grapharea_pen)
        dc.SetBrush(self.no_brush)
        dc.DrawRectangle(ga[0][0], ga[0][1], ga[1][0]-ga[0][0], (ga[1][1]-ga[0][1])+1)
        
        # draw text
        dc.SetFont(wx.Font(xaxis_text[1], wx.SWISS, wx.NORMAL, wx.NORMAL))
        dc.SetTextForeground(self.gp_grapharea_f)
        tsize = dc.GetTextExtent(xaxis_text[0])
        center = ((ga[1][0]-ga[0][0])/ 2) + ga[0][0]
        dc.DrawText(xaxis_text[0], int(center - tsize[0]/2), ( ga[1][1] + 0))
        
        tsize = dc.GetTextExtent(yaxis_text[0])
        h1 = ga[0][1]
        h2 = (ga[1][1] - ga[0][1]) / 2
        h3 = tsize[0]/2
        center = int(  h1 + h2 + h3 )
        dc.SetFont(wx.Font(yaxis_text[1], wx.SWISS, wx.NORMAL, wx.NORMAL))
        dc.DrawRotatedText(yaxis_text[0], 2, center, 90)
        
    def AcceptsFocus(self):
        """ Overridden base class virtual. """
        return False
    
    def DoGetBestSize(self):
        """ Overridden base class virtual. """
        return self.size    
